package com.gitee.wsl.ext.collection

import com.gitee.wsl.func.predicate.Predicate


fun <T> Iterable<T>.isUnique() = toSet().size == 1
fun <T> Iterable<T>.uniqueValue(): T? = toSet().singleOrNull()
inline fun <T, U> Iterable<T>.uniqueOn(block: (T) -> U) = map(block).isUnique()
inline fun <T, U> Iterable<T>.uniqueValue(block: (T) -> U): U? = map(block).uniqueValue()

fun <T> Sequence<T>.isUnique() = toSet().size == 1
fun <T> Sequence<T>.uniqueValue(): T? = toSet().singleOrNull()
fun <T, U> Sequence<T>.uniqueOn(block: (T) -> U) = map(block).isUnique()
fun <T, U> Sequence<T>.uniqueValue(block: (T) -> U): U? = map(block).uniqueValue()


inline fun <T, R> Iterable<T>.allUniqueBy(transform: (T) -> R): Boolean {
    val hashset = hashSetOf<R>()
    return this.all { hashset.add(transform(it)) }
}

/**
 * Checks, if a unique elements exists such that the predicate holds.
 *
 * @param predicate A Predicate
 * @return true, if predicate holds for a unique element, false otherwise
 * @throws NullPointerException if `predicate` is null
 */
fun<T> Iterable<T>.existsUnique(predicate: Predicate<in T>): Boolean {
    var exists = false
    for (t in this) {
        if (predicate.test(t)) {
            if (exists) {
                return false
            } else {
                exists = true
            }
        }
    }
    return exists
}
